package com.duobaoyu.dby.supply.admin.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.duobaoyu.dby.channel.adapter.enums.ChannelCodeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.order.OrderStatusEnum;
import com.duobaoyu.dby.common.core.constant.CommonConstants;
import com.duobaoyu.dby.common.core.service.CacheTemplate;
import com.duobaoyu.dby.common.mybatis.util.EnumUtils;
import com.duobaoyu.dby.supply.admin.service.BalanceChangeInfoService;
import com.duobaoyu.dby.supply.biz.client.boundary.account.AccountBoundaryClient;
import com.duobaoyu.dby.supply.biz.client.boundary.account.bean.bo.BalanceInfoBO;
import com.duobaoyu.dby.supply.biz.enums.RedisKeys;
import com.duobaoyu.dby.supply.biz.service.order.OrderProductService;
import com.duobaoyu.dby.supply.biz.service.order.OrderService;
import com.duobaoyu.dby.supply.common.biz.bo.order.OrderAmountStatisticsBO;
import com.duobaoyu.dby.supply.common.biz.bo.product.OrderProductSellCountBO;
import com.duobaoyu.dby.supply.common.biz.dto.account.BalanceInfoDTO;
import com.duobaoyu.dby.supply.common.biz.dto.order.OrderProductStatisticsDTO;
import com.duobaoyu.dby.supply.common.biz.dto.order.OrderStatisticsAmountDTO;
import com.duobaoyu.dby.supply.common.biz.vo.account.AvailableBalanceVO;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class BalanceChangeInfoServiceImpl implements BalanceChangeInfoService {

    private final OrderService orderService;
    private final OrderProductService orderProductService;
    private final ThreadPoolExecutor supplyChainThreadPool;
    private final AccountBoundaryClient accountBoundaryClient;
    private final CacheTemplate<List<AvailableBalanceVO>> cacheTemplate;

    @Override
    public List<AvailableBalanceVO> queryBalanceAndCount(BalanceInfoDTO balanceInfo) {
        Boolean refresh = Optional.ofNullable(balanceInfo).map(BalanceInfoDTO::getIfRefresh).orElse(false);
        if(refresh) {
            cacheTemplate.remove(RedisKeys.CHANNEL_BALANCE_KEY.key());
        }
        List<AvailableBalanceVO> availableBalanceList = cacheTemplate.findCache(RedisKeys.CHANNEL_BALANCE_KEY.key(), CommonConstants.ONE, TimeUnit.DAYS, new TypeReference<List<AvailableBalanceVO>>() {
        }, () -> {
            List<BalanceInfoBO> balanceInfos = accountBoundaryClient.channelBalanceInfos();
            List<String> channelCodeList = balanceInfos.stream().map(BalanceInfoBO::getChannelCode).collect(Collectors.toList());
            LocalDateTime startLocalDateTime = LocalDateTime.now().minusDays(90);
            // 统计订单金额
            CompletableFuture<List<OrderAmountStatisticsBO>> completableFuture = CompletableFuture.supplyAsync(() -> {
                ArrayList<Integer> statusList = Lists.newArrayList(OrderStatusEnum.WAIT_PAY.getValue()
                        , OrderStatusEnum.RECHARGE.getValue()
                        , OrderStatusEnum.WAIT_SHIP.getValue()
                        , OrderStatusEnum.PART_SEND.getValue()
                        , OrderStatusEnum.SHIPPED.getValue()
                        , OrderStatusEnum.CANCELLING.getValue()
                        , OrderStatusEnum.MANUAL_HANDLING.getValue());
                OrderStatisticsAmountDTO orderStatisticsAmount = OrderStatisticsAmountDTO.builder().startCreateTime(startLocalDateTime).channelCodeList(channelCodeList).statusList(statusList).build();
                return orderService.statisticsAmount(orderStatisticsAmount);
            }, supplyChainThreadPool);

            // 统计商品销量
            CompletableFuture<List<OrderProductSellCountBO>> completableFuture1 = CompletableFuture.supplyAsync(() -> {
                OrderProductStatisticsDTO orderProductStatistics = OrderProductStatisticsDTO.builder()
                        .statusList(Lists.newArrayList(OrderStatusEnum.RECHARGE.getValue(),
                                OrderStatusEnum.WAIT_SHIP.getValue(),
                                OrderStatusEnum.PART_SEND.getValue(),
                                OrderStatusEnum.SHIPPED.getValue(),
                                OrderStatusEnum.PART_SUCCESS.getValue(),
                                OrderStatusEnum.COMPLETE.getValue(),
                                OrderStatusEnum.CANCELLING.getValue(),
                                OrderStatusEnum.MANUAL_HANDLING.getValue())).channelCodeList(channelCodeList).build();
                return orderProductService.statisticsProductSellCount(orderProductStatistics);
            }, supplyChainThreadPool);
            Map<String, List<OrderAmountStatisticsBO>> channelOrderStatusAmount = completableFuture.join().stream().collect(Collectors.groupingBy(OrderAmountStatisticsBO::getChannelCode));
            Map<String, OrderProductSellCountBO> channelProductSellCount = completableFuture1.join().stream().collect(Collectors.toMap(OrderProductSellCountBO::getChannelCode, Function.identity()));
            return balanceInfos.stream().map(item -> {
                AvailableBalanceVO availableBalance = new AvailableBalanceVO();
                ChannelCodeEnum channelCodeEnum = ChannelCodeEnum.getChannelCodeEnumByCode(item.getChannelCode());
                availableBalance.setChannelCode(channelCodeEnum.getValue());
                availableBalance.setChannelName(channelCodeEnum.getDescribe());
                availableBalance.setAvailableBalance(item.getAccountBalance());
                // 设置预下单金额和在途金额
                List<OrderAmountStatisticsBO> orderAmountStatisticsList = channelOrderStatusAmount.get(channelCodeEnum.getValue());
                if (CollectionUtils.isNotEmpty(orderAmountStatisticsList)) {
                    for (OrderAmountStatisticsBO orderAmountStatistics : orderAmountStatisticsList) {
                        if (EnumUtils.eq(OrderStatusEnum.WAIT_PAY, orderAmountStatistics.getStatus())) {
                            availableBalance.setPreOrderAmount(availableBalance.getPreOrderAmount().add(availableBalance.getPreOrderAmount()));
                        } else {
                            availableBalance.setLockAmount(availableBalance.getLockAmount().add(availableBalance.getPreOrderAmount()));
                        }
                    }
                }
                // 设置销量
                Optional.ofNullable(channelProductSellCount.get(channelCodeEnum.getValue()))
                        .ifPresent(sellCount -> availableBalance.setSellCount(sellCount.getSellCount()));
                return availableBalance;
            }).collect(Collectors.toList());
        });

		if(ObjectUtils.isNotEmpty(balanceInfo) && StringUtils.isNotBlank(balanceInfo.getChannelCode())) {
            return availableBalanceList.stream().filter(item -> Objects.equals(balanceInfo.getChannelCode(),item.getChannelCode())).collect(Collectors.toList());
        } else {
            return availableBalanceList;
        }
    }
}
